package com.dp.mallchat.common.user.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dp.mallchat.common.common.event.BlackEvent;
import com.dp.mallchat.common.common.event.UserRegisterEvent;
import com.dp.mallchat.common.common.utils.AssertUtil;
import com.dp.mallchat.common.user.dao.BlackDao;
import com.dp.mallchat.common.user.dao.ItemConfigDao;
import com.dp.mallchat.common.user.dao.UserBackpackDao;
import com.dp.mallchat.common.user.dao.UserDao;
import com.dp.mallchat.common.user.domain.user.entity.Black;
import com.dp.mallchat.common.user.domain.user.entity.ItemConfig;
import com.dp.mallchat.common.user.domain.user.entity.User;
import com.dp.mallchat.common.user.domain.user.entity.UserBackpack;
import com.dp.mallchat.common.user.domain.user.enums.BlackTypeEnum;
import com.dp.mallchat.common.user.domain.user.enums.ItemEnum;
import com.dp.mallchat.common.user.domain.user.enums.ItemTypeEnum;
import com.dp.mallchat.common.user.domain.user.req.*;
import com.dp.mallchat.common.user.domain.user.resp.BadgeResp;
import com.dp.mallchat.common.user.domain.user.resp.ItemInfoDTO;
import com.dp.mallchat.common.user.domain.user.resp.SummeryInfoDTO;
import com.dp.mallchat.common.user.domain.user.resp.UserInfoResp;
import com.dp.mallchat.common.user.mapper.UserMapper;
import com.dp.mallchat.common.user.service.UserService;
import com.dp.mallchat.common.user.service.adapter.UserAdapter;
import com.dp.mallchat.common.user.service.cache.ItemConfigCache;
import com.dp.mallchat.common.user.service.cache.UserCache;
import com.dp.mallchat.common.user.service.cache.UserSummaryCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author: dupeng
 * @CreateTime: 2024-06-03  16:29
 * @Description: 用户实现
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserBackpackDao userBackpackDao;
    @Autowired
    private ItemConfigCache itemConfigCache;
    @Autowired
    private BlackDao blackDao;
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private UserCache userCache;
    @Autowired
    private UserSummaryCache userSummaryCache;

    @Override
    public void register(User user) {
        userDao.registerUser(user);
        //发放改名卡事件
        applicationEventPublisher.publishEvent(new UserRegisterEvent(this, user));
    }

    @Override
    public UserInfoResp getUserInfo(Long uid) {
        User user = userDao.getById(uid);
        Integer waitUseCount = userBackpackDao.getCountByUidAndItemId(uid, ItemEnum.MODIFY_NAME_CARD.getId());
        return UserAdapter.buildUserInfoResp(user, waitUseCount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyName(Long uid, ModifyNameReq modifyNameReq) {
        //用户存在改名卡
        UserBackpack userBackpack = userBackpackDao.getFistValidItem(uid, ItemEnum.MODIFY_NAME_CARD.getId());
        AssertUtil.isNotEmpty(userBackpack, "您还没有改名卡");
        //用户昵称是否重复
        User user = userDao.getByName(uid, modifyNameReq.getName());
        AssertUtil.isFalse(Objects.nonNull(user) && uid.equals(user.getId()), "这个名字已经属于您了呢~");
        AssertUtil.isEmpty(user, "名称重复了，换一下吧");
        // 修改用户名
        userDao.updateById(uid, modifyNameReq.getName());
        // 修改背包中对应道具的数量
        boolean isSuccess = userBackpackDao.updateCountByUidAndItemId(userBackpack.getId());
        AssertUtil.isTrue(isSuccess, "修改背包失败，请稍后再试");
    }


    @Override
    public List<BadgeResp> badges(Long uid) {
        //所有徽章
        List<ItemConfig> itemConfigList = itemConfigCache.listAll(ItemTypeEnum.BADGE.getType());
        //用户拥有的徽章
        List<Long> itemId = itemConfigList.stream().map(ItemConfig::getId).collect(Collectors.toList());
        List<UserBackpack> userBackpackList = userBackpackDao.listBadgeByUid(uid, itemId);
        //用户佩戴哪些徽章
        User user = userDao.getById(uid);
        return UserAdapter.buildBadgesBuild(itemConfigList, userBackpackList, user);
    }

    @Override
    public void wearingBadge(Long uid, BadgeReq badgeReq) {
        Long badgeId = Long.valueOf(badgeReq.getBadgeId());
        //徽章是否有效
        List<ItemConfig> itemConfigs = itemConfigCache.listAll(ItemTypeEnum.BADGE.getType());
        boolean isContains = itemConfigs.stream().map(ItemConfig::getId).collect(Collectors.toList()).contains(badgeId);
        AssertUtil.isTrue(isContains, "徽章不存在");
        //是否拥有此徽章
        UserBackpack userBackpack = userBackpackDao.getFistValidItem(uid, badgeId);
        AssertUtil.isNotEmpty(userBackpack, "您还没有此徽章");
        //佩戴
        userDao.wearingBadgeById(uid, badgeId);
    }


    @Override
    public void black(BlackReq req) {
        //拉黑uid
        blackIp(req.getUid(), BlackTypeEnum.UID.getType());

        //拉黑ip
        User user = userDao.getById(req.getUid());
        blackIp(user.getIpInfo().getCreateIp(), BlackTypeEnum.IP.getType());
        blackIp(user.getIpInfo().getUpdateIp(), BlackTypeEnum.IP.getType());

        //拉黑事件
        applicationEventPublisher.publishEvent(new BlackEvent(this, user));
    }

    @Override
    public List<SummeryInfoDTO> getSummeryUserInfo(SummeryInfoReq req) {
        //返回需要更新的uid(uid依据前端传递)
        List<Long> uidList = getNeedSyncUidList(req.getReqList());
        //加载用户信息
        Map<Long, SummeryInfoDTO> batch = userSummaryCache.getBatch(uidList);
        return req.getReqList()
                .stream()
                .map(a -> batch.containsKey(a.getUid()) ? batch.get(a.getUid()) : SummeryInfoDTO.skip(a.getUid()))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    @Override
    public List<ItemInfoDTO> getItemInfo(ItemInfoReq req) {
        return req.getReqList().stream().map(a -> {
            ItemConfig itemConfig = itemConfigCache.getById(a.getItemId());
            if (Objects.nonNull(a.getLastModifyTime()) && a.getLastModifyTime() >= itemConfig.getUpdateTime().getTime()) {
                return ItemInfoDTO.skip(a.getItemId());
            }
            ItemInfoDTO dto = new ItemInfoDTO();
            dto.setItemId(itemConfig.getId());
            dto.setImg(itemConfig.getImg());
            dto.setDescribe(itemConfig.getDescribe());
            return dto;
        }).collect(Collectors.toList());
    }

    private List<Long> getNeedSyncUidList(List<SummeryInfoReq.InfoReq> reqList) {
        List<Long> needSyncUidList = new ArrayList<>();     // 最终需要更新的uid
        //获取用户最新的一次更新时间
        List<Long> userModifyTime = userCache.getUserModifyTime(reqList.stream().map(SummeryInfoReq.InfoReq::getUid).collect(Collectors.toList()));
        //收集需要更新uid
        for (int i = 0; i < reqList.size(); i++) {
            SummeryInfoReq.InfoReq infoReq = reqList.get(i);
            Long modifyTime = userModifyTime.get(i);
            //前端传递时间为空，缓存时间 > 前端传递时间，以上场景都需更新用户最新数据
            if (Objects.isNull(infoReq.getLastModifyTime()) || (Objects.nonNull(modifyTime) && modifyTime > infoReq.getLastModifyTime())) {
                needSyncUidList.add(infoReq.getUid());
            }
        }
        return needSyncUidList;
    }

    private void blackIp(Object target, Integer type) {
        if (Objects.isNull(target)) {
            return;
        }
        try {
            Black black = new Black();
            black.setType(type);
            black.setTarget(target.toString());
            blackDao.save(black);
        } catch (DuplicateKeyException ignored) {
            log.error("duplicate black ip:{}", target);
        }
    }
}
